﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Media.Imaging;

namespace SL8.SL.Controls
{
    [TemplatePart(Name = TiledImage.PART_FillImage, Type = typeof(Image))]
    public class TiledImage : Control
    {
        private const string PART_FillImage = "FillImage";

        private BitmapImage bitmap;
        private int lastHeight = 0;
        private int lastWidth;
        private WriteableBitmap sourceBitmap;

        public static readonly DependencyProperty SourceUriProperty = DependencyProperty.Register("SourceUri", typeof(Uri), typeof(TiledImage), new PropertyMetadata(null, new PropertyChangedCallback(TiledImage.OnSourceUriChanged)));


        public Uri SourceUri
        {
            get
            {
                return (Uri)base.GetValue(TiledImage.SourceUriProperty);
            }

            set
            {
                base.SetValue(TiledImage.SourceUriProperty, value);
            }
        }

        internal Image FillImage
        {
            get;
            private set;
        }

        public TiledImage()
        {
            this.DefaultStyleKey = typeof(TiledImage);
            base.SizeChanged += new SizeChangedEventHandler(TiledImage_SizeChanged);
        }

        void TiledImage_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.UpdateTiledImage();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.FillImage = this.GetTemplateChild(TiledImage.PART_FillImage) as Image;
            this.UpdateTiledImage();
        }

        private static void OnSourceUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((TiledImage)d).OnSourceUriChanged(e);
        }

        protected virtual void OnSourceUriChanged(DependencyPropertyChangedEventArgs e)
        {
            if (this.bitmap != null)
            {
                this.bitmap.ImageFailed -= new EventHandler<ExceptionRoutedEventArgs>(bitmap_ImageFailed);
                this.bitmap.ImageOpened -= new EventHandler<RoutedEventArgs>(this.bitmap_ImageOpened);
            }

            Uri uri = e.NewValue as Uri;

            if (uri == null)
            {
                this.ClearTiledImage();
                return;
            }

            this.bitmap = new BitmapImage(uri);
            this.bitmap.CreateOptions = BitmapCreateOptions.None;
            this.bitmap.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(bitmap_ImageFailed);
            this.bitmap.ImageOpened += new EventHandler<RoutedEventArgs>(this.bitmap_ImageOpened);
        }

        void bitmap_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            this.ClearTiledImage();
        }

        private void bitmap_ImageOpened(object sender, RoutedEventArgs e)
        {
            this.sourceBitmap = new WriteableBitmap(this.bitmap);
            this.UpdateTiledImage();
        }

        private void UpdateTiledImage()
        {
            if (this.sourceBitmap != null && this.FillImage != null)
            {
                int pixelWidth = (int)Math.Ceiling(base.ActualWidth);
                int pixelHeight = (int)Math.Ceiling(base.ActualHeight);
                if ((pixelWidth >= this.lastWidth) || (pixelHeight >= this.lastHeight) || this.FillImage.Source == null)
                {
                    this.lastWidth = pixelWidth;
                    this.lastHeight = pixelHeight;
                    WriteableBitmap bitmap = new WriteableBitmap(pixelWidth, pixelHeight);
                    for (int i = 0; i < bitmap.PixelWidth; i++)
                    {
                        for (int j = 0; j < bitmap.PixelHeight; j++)
                        {
                            int num5 = i % this.sourceBitmap.PixelWidth;
                            int num6 = j % this.sourceBitmap.PixelHeight;
                            bitmap.Pixels[(j * bitmap.PixelWidth) + i] = this.sourceBitmap.Pixels[(num6 * this.sourceBitmap.PixelWidth) + num5];
                        }
                    }

                    this.FillImage.Source = bitmap;
                }
            }
        }

        private void ClearTiledImage()
        {
            this.sourceBitmap = null;
            if (this.FillImage != null)
            {
                this.FillImage.Source = null;
            }
        }
    }
}
